package it.prova.transform;

import it.prova.Consts;
import it.prova.Utility;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URI;

import nu.xom.Attribute;
import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Nodes;
import nu.xom.ParsingException;
import nu.xom.Text;

import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.filesystem.IFileSystem;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jst.pagedesigner.dtmanager.converter.operations.AbstractTransformOperation;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class MultiDataUnitTransformOperation extends AbstractTransformOperation
{	
	private Document currentModel;
	
	public Element transform(Element sourceElement, Element displayElement)
	{
		if(tagConverterContext == null)
		{
			return displayElement;
		}
		
		String var = sourceElement.getAttribute(Consts.MODEL_ATTRIBUTE_NAME);
		
//		Element iterateElement = Utility.getFirstParentElementByTagName(sourceElement, Consts.TAG_ITERATE_NAME);
//		
//		// as default, only one iteration
//		int iterationNumber = 1;
//		if(iterateElement != null)
//		{
//			try
//			{
//				iterationNumber = Integer.parseInt(iterateElement.getAttribute(Consts.NUMBER_ATTRIBUTE_NAME));
//			}
//			catch(NumberFormatException nfe)
//			{
//				
//			}
//		}
				
		Element firstDiv = tagConverterContext.createElement("webratio");
		Element secondDiv = tagConverterContext.createElement("webratio");
//		secondDiv.setAttribute("class", "pippo");
		
		currentModel = Utility.getCurrentModel(Consts.MULTI_DATA_UNIT);
		
		if(currentModel != null)
		{
			Nodes attributes = currentModel.query
			(
				Consts.MODEL_ATTRIBUTE_QUERY + "[@" + Consts.MODEL_ENTITY_ATTRIBUTE_NAME + "=\"" + Utility.getEntityName(currentModel) + 
				"\"]/" + Consts.MODEL_ATTRIBUTE_TAG + "[@" + Consts.MODEL_ATTRIBUTE_NAME + "=\"" + var + "\"]/" + 
				sourceElement.getLocalName()
			);
			
			nu.xom.Element attribute = null;
			if(attributes.size() > 1)
			{
				System.out.println("More than one tag with '" + var + "' value for '" + Consts.MODEL_ATTRIBUTE_NAME + "' attribute in current model");
			}
			else if(attributes.size() <= 0)
			{
				// if not found in current model, I have to search in default model
				Document doc = null;
				try
				{
					IFileSystem fileSystem = EFS.getLocalFileSystem();
					IFileStore defaultTemplateFileStore = fileSystem.getStore(URI.create(Consts.MULTI_DATA_UNIT_MODEL_FILE_PATH));
					
					Builder parser = new Builder();
					doc = parser.build(new BufferedInputStream(defaultTemplateFileStore.openInputStream(EFS.NONE, null)));
				}
				catch(CoreException ce)
				{
					ce.printStackTrace();
				}
				catch(IOException ioe)
				{
					ioe.printStackTrace();
				}
				catch(ParsingException pe)
				{
					pe.printStackTrace();
				}
				
				Nodes attributesIn = doc.query
				(
					Consts.MODEL_ATTRIBUTE_QUERY + "[@" + Consts.MODEL_ENTITY_ATTRIBUTE_NAME + "=\"" + Utility.getEntityName(currentModel) + 
					"\"]/" + Consts.MODEL_ATTRIBUTE_TAG + "[@" + Consts.MODEL_ATTRIBUTE_NAME + "=\"" + var + "\"]/" + 
					sourceElement.getLocalName()
				);
				
				if(attributesIn.size() > 1)
				{
					System.out.println("More than one tag with '" + var + "' value for '" + Consts.MODEL_ATTRIBUTE_NAME + "' attribute in default model");
				}
				else if(attributesIn.size() <= 0)
				{
					System.out.println("No tag with '" + var + "' value for '" + Consts.MODEL_ATTRIBUTE_NAME + "' attribute in default model");
				}
				else
				{
					attribute = (nu.xom.Element) attributesIn.get(0);
				}
			}
			else
			{
				// found in current model
				attribute = (nu.xom.Element) attributes.get(0);
			}
			
			if(attribute != null)
			{
				String value = attribute.getValue().trim();
				
				if((value != null) && (value.length() > 0))
				{
					System.out.println("value = " + value);
					System.out.println("sourceElement.getLocalName() = " + sourceElement.getLocalName());
					if(Consts.TAG_VALUE_NAME.equals(sourceElement.getLocalName()))
					{
						Attribute typeAttr = ((nu.xom.Element) attribute.getParent()).getAttribute(Consts.MODEL_ATTRIBUTE_TYPE);
						
						if(typeAttr != null)
						{
							String typeVal = typeAttr.getValue();
							if(Consts.ATTRIBUTE_TYPE_STRING.equals(typeVal))
							{
								value = value.replaceAll(Consts.WR_PLACE_HOLDER_ESCAPED, "abcdefghil");
							}
							else if(Consts.ATTRIBUTE_TYPE_INT.equals(typeVal))
							{
								value = value.replaceAll(Consts.WR_PLACE_HOLDER_ESCAPED, "1234567890");
							}
							else if(Consts.ATTRIBUTE_TYPE_DATE.equals(typeVal))
							{
								value = value.replaceAll(Consts.WR_PLACE_HOLDER_ESCAPED, "31/12/2010");
							}
							else if(Consts.ATTRIBUTE_TYPE_PASSWORD.equals(typeVal))
							{
								value = value.replaceAll(Consts.WR_PLACE_HOLDER_ESCAPED, "**********");
							}
						}
					}
					else if(Consts.TAG_LABEL_NAME.equals(sourceElement.getLocalName()))
					{
						value = value.replaceAll(Consts.WR_PLACE_HOLDER_ESCAPED, sourceElement.getAttribute(Consts.MODEL_ATTRIBUTE_NAME));
					}
					
					Document xom = null;
					try
					{
						Builder parser = new Builder();
						xom = parser.build(new ByteArrayInputStream(value.getBytes()));
					}
					catch(Exception e)
					{
						
					}
					
//					for(int j=0; j<iterationNumber; j++)
//					{
						if(xom != null)
						{
							nu.xom.Element root = xom.getRootElement();
							
							Element elem = getElementsFromXOM(root);
							
							NodeList nodes = elem.getChildNodes();
							for(int i=0; i<nodes.getLength(); i++)
							{
								secondDiv.appendChild(nodes.item(i));
							}
						}
						else
						{
							org.w3c.dom.Text textvalue = tagConverterContext.createText(value);
							secondDiv.appendChild(textvalue);
						}
//					}
				}
			}
			
			// default behaviour
			if(secondDiv.getChildNodes().getLength() == 0)
			{
//				for(int j=0; j<iterationNumber; j++)
//				{
					Element p = tagConverterContext.createElement("p");
					
					p.appendChild(tagConverterContext.createText
					(
						"<" + sourceElement.getPrefix() + ":" +
						sourceElement.getLocalName() + " />"
					));
					
					secondDiv.appendChild(p);
//				}
			}
			// if this tag is inside an Iterate one, I have to transform it too
//			else
//			{
//				Element iterateParent = Utility.getFirstParentElementByTagName(sourceElement, Consts.TAG_ITERATE_NAME);
//				if(iterateParent != null)
//				{
//					MultiDataUnitIterateTransformOperation transform = new MultiDataUnitIterateTransformOperation();
//					transform.setTagConverterContext(tagConverterContext);
//					transform.transform(iterateParent, iterateParent);
//				}
//			}
			tagConverterContext.copyChildren(sourceElement, secondDiv);
		}
		
		firstDiv.appendChild(secondDiv);
		
		return firstDiv;
	}
	
	private Element getElementsFromXOM(nu.xom.Element element)
	{
		Element resultElement = tagConverterContext.createElement(element.getLocalName());
		
		for(int i=0; i<element.getAttributeCount(); i++)
		{
			Attribute attr = element.getAttribute(i);
			resultElement.setAttribute(attr.getLocalName(), attr.getValue());
		}
		
		for(int i=0; i<element.getChildCount(); i++)
		{
			nu.xom.Node node = element.getChild(i);
			
			if(node instanceof nu.xom.Element)
			{
				nu.xom.Element e = (nu.xom.Element) node;
				
				resultElement.appendChild(getElementsFromXOM(e));
			}
			else if(node instanceof nu.xom.Document)
			{
				nu.xom.Document d = (nu.xom.Document) node;
				nu.xom.Element e = d.getRootElement();
				
				resultElement.appendChild(getElementsFromXOM(e));
			}
			else if(node instanceof nu.xom.Text)
			{
				Text t = (Text) node;
				String s = t.getValue();
				
				resultElement.appendChild(tagConverterContext.createText(s));
			}
			else if(node instanceof nu.xom.Comment)
			{
				// skipping comments
			}
			else if(node instanceof nu.xom.Attribute)
			{
				Attribute a = (Attribute) node;
				
				resultElement.setAttribute(a.getLocalName(), a.getValue());
			}
			else if(node instanceof nu.xom.ProcessingInstruction)
			{
				// skipping processing instructions
			}
			else if(node instanceof nu.xom.DocType)
			{
				// skipping document type declarations
			}
			else if(node instanceof nu.xom.Namespace)
			{
				// skipping namespaces
			}
		}
		return resultElement;
	}
}